package myzzyl.service.Impl;

import cn.dev33.satoken.context.mock.SaTokenContextMockUtil;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import myzzyl.constants.CommonStrField;
import myzzyl.constants.ErrorConstants;
import myzzyl.domain.dto.LoginDto;
import myzzyl.domain.dto.SysUserDto;
import myzzyl.domain.pojo.JwtUser;
import myzzyl.domain.pojo.SysUser;
import myzzyl.domain.pojo.SysUserRole;
import myzzyl.domain.vo.SysUserVo;
import myzzyl.exception.BusinessException;
import myzzyl.properties.JwtProperties;
import myzzyl.properties.SecurityConfigProperties;
import myzzyl.response.PageResponse;
import myzzyl.service.SysResourceService;
import myzzyl.service.SysRoleService;
import myzzyl.service.SysUserRoleService;
import myzzyl.service.SysUserService;
import myzzyl.mapper.SysUserMapper;
import myzzyl.utils.JwtUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
* @author 33249
* @description 针对表【sys_user(用户表)】的数据库操作Service实现
* @createDate 2025-08-17 16:23:55
*/
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser>
    implements SysUserService {


    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Autowired
    private SysRoleService sysRoleService;

//    @Autowired
//    private SysResourceService sysResourceService;
//
//    @Autowired
//    private StringRedisTemplate stringRedisTemplate;
//
//    @Autowired
//    private SecurityConfigProperties securityConfigProperties;
//
//    @Autowired
//    private JwtProperties jwtProperties;

    /**
     * 获取默认列表数据
     * @return 返回值
     */
    @Override
    public List<SysUser> getAll() {
        return list();
    }


    /**
     * 分页获取用户列表数据
     * @param pageNum 页码
     * @param pageSize 每页大小
     * @param sysUserDto 用户请求表单封装类
     * @return 返回值
     */
    @Override
    public PageResponse<SysUserVo> pageQuery(Integer pageNum, Integer pageSize, SysUserDto sysUserDto) {
        // 创建分页对象
        Page<SysUser> page = new Page<>(pageNum, pageSize);

        // 添加排序字段
        page.addOrder(OrderItem.desc("create_time"));

        // 分页查询
        IPage<SysUserVo> sysUserVoIPage = baseMapper.selectSysUserVoList(page, sysUserDto);

        // 遍历查询到的集合，查询用户绑定的角色id和角色名称并设置
        sysUserVoIPage.getRecords().forEach(sysUserVo -> {
            List<SysUserRole> sysUserRoleList = sysUserRoleService.lambdaQuery()
                    .eq(SysUserRole::getUserId, sysUserVo.getId())
                    .list();

            Set<String> roleIds = new HashSet<>();
            Set<String> roleLabels = new HashSet<>();

            sysUserRoleList.forEach(sysUserRole -> {
                // 根据角色id查询对应的角色名称
                String roleName = sysRoleService.getById(sysUserRole.getRoleId()).getRoleName();
                roleLabels.add(roleName);
                roleIds.add(sysUserRole.getRoleId().toString());
            });

            sysUserVo.setRoleVoIds(roleIds);
            sysUserVo.setRoleLabels(roleLabels);
        });

        return new PageResponse<>(sysUserVoIPage.getPages(), sysUserVoIPage.getTotal(), sysUserVoIPage.getRecords());
    }

    /**
     * 新增用户
     * @param sysUserDto 用户请求表单封装类
     * @return 返回值
     */
    @Override
    @Transactional
    public boolean add(SysUserDto sysUserDto) {
        // 查询用户是否已经存在
        if (lambdaQuery()
                .eq(SysUser::getRealName, sysUserDto.getRealName())
                .exists()) {
            throw new BusinessException(ErrorConstants.USER_IS_ALREADY_EXIST);
        }

        // 保存用户
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(sysUserDto, sysUser);
        sysUser.setDataState("0");
        sysUser.setIsLeader(0);
        // 账号UUID前16未，用户名nick_ + 手机号后四位，密码使用123456经BCrypt加密后的字符串
        sysUser.setUsername(IdUtil.fastSimpleUUID().substring(0, 16));
        sysUser.setNickName("nick_" + sysUserDto.getMobile().substring(7));
        sysUser.setPassword(BCrypt.hashpw(CommonStrField.DEFAULT_PASSWORD.getStr()));

        boolean isSuccess = save(sysUser);
        if (isSuccess) {
            List<SysUserRole> sysUserRoles = getSysUserRoles(sysUserDto.getRoleVoIds(), sysUser.getId());
            return sysUserRoleService.saveBatch(sysUserRoles);
        }
        return false;
    }


    /**
     * 编辑用户
     * @param sysUserDto 用户请求表单封装类
     * @return 返回值
     */
    @Override
    public boolean edit(SysUserDto sysUserDto) {
        // 查询用户是否已经存在（除去自己）
        if (lambdaQuery()
                .eq(SysUser::getRealName, sysUserDto.getRealName())
                .ne(SysUser::getId, sysUserDto.getId())
                .exists()) {
            throw new BusinessException(ErrorConstants.USER_IS_ALREADY_EXIST);
        }

        // 修改用户
        boolean isSuccess = lambdaUpdate()
                .set(SysUser::getRealName, sysUserDto.getRealName())
                .set(SysUser::getDeptNo, sysUserDto.getDeptNo())
                .set(SysUser::getPostNo, sysUserDto.getPostNo())
                .set(SysUser::getEmail, sysUserDto.getEmail())
                .set(SysUser::getMobile, sysUserDto.getMobile())
                .set(SysUser::getSex, sysUserDto.getSex())
                .eq(SysUser::getId, sysUserDto.getId())
                .update();
        if (isSuccess) {
            // 先删除用户原先绑定的角色，再批量新增
            sysUserRoleService.deleteByUserId(sysUserDto.getId());
            List<SysUserRole> sysUserRoles = getSysUserRoles(sysUserDto.getRoleVoIds(), sysUserDto.getId());

            return sysUserRoleService.saveBatch(sysUserRoles);
        }
        return false;
    }

    /**
     * 获取要批量新增的用户-角色数据
     * @param roleIds 用户绑定的角色编号
     * @param userId 用户id
     * @return 返回值
     */
    private List<SysUserRole> getSysUserRoles(Set<String> roleIds, Long userId) {
        // 批量保存用户绑定的角色
        return roleIds.stream()
                      .map(roleId -> {
                        // 构造sysUserRole对象返回
                        SysUserRole sysUserRole = new SysUserRole();
                        sysUserRole.setUserId(userId);
                        sysUserRole.setRoleId(Long.parseLong(roleId));

                        return sysUserRole;
                      }).toList();
    }


    /**
     * 删除用户
     * @param id 用户id
     * @return 返回值
     */
    @Override
    public boolean deleteUserById(Long id) {
        // 查询用户是否存在
        SysUser user = getById(id);
        if (user == null) {
            throw new BusinessException(ErrorConstants.USER_IS_NOT_EXIST);
        }

        // 判断状态是否为启用
        if (user.getDataState().equals("0")) {
            throw new BusinessException(ErrorConstants.USER_IS_ACTIVE);
        }

        // 更新用户的逻辑删除字段
        boolean isSuccess = lambdaUpdate()
                .set(SysUser::getIsDelete, null)
                .eq(SysUser::getId, id)
                .update();
        if (isSuccess) {
            sysUserRoleService.deleteByUserId(id);
            return true;
        }
        return false;
    }


    /**
     * enableOrDisableUser
     * @param id 用户id
     * @param status 更新的状态
     * @return 返回值
     */
    @Override
    public boolean enableOrDisableUser(Long id, String status) {
        // 查询用户是否存在
        if (!lambdaQuery().eq(SysUser::getId, id).exists()) {
            throw new BusinessException(ErrorConstants.USER_IS_NOT_EXIST);
        }

        // 更新状态值
        return lambdaUpdate()
                .set(SysUser::getDataState, status)
                .eq(SysUser::getId, id)
                .update();
    }

    /**
     * 重置密码
     * @param id 用户id
     * @return 返回值
     */
    @Override
    public boolean resetPassword(Long id) {
        // 查询用户是否存在
        if (!lambdaQuery().eq(SysUser::getId, id).exists()) {
            throw new BusinessException(ErrorConstants.USER_IS_NOT_EXIST);
        }

        // 更新密码
        return lambdaUpdate()
                .set(SysUser::getPassword, BCrypt.hashpw(CommonStrField.DEFAULT_PASSWORD.getStr()))
                .eq(SysUser::getId, id)
                .update();
    }


//    /**
//     * 用户登录
//     * @param loginDto 用户登录表单请求封装类
//     * @return 返回值
//     */
//    @Override
//    public SysUserVo login(LoginDto loginDto) {
//        // 查询账号是否存在
//        SysUser user = lambdaQuery()
//                .eq(SysUser::getUsername, loginDto.getUsername())
//                .one();
//        if (user == null) {
//            throw new BusinessException(ErrorConstants.USER_ACCOUNT_IS_NOT_EXIST);
//        }
//
//        // 判断账号是否禁用
//        if (user.getDataState().equals("1")) {
//            throw new BusinessException(ErrorConstants.USER_ACCOUNT_IS_FORBIDDEN);
//        }
//        // 判断密码是否正确
//        if (!BCrypt.checkpw(loginDto.getPassword(), user.getPassword())) {
//            throw new BusinessException(ErrorConstants.USER_ACCOUNT_OR_PASSWORD_ERROR);
//        }
//
//        // 查询用户绑定的资源
//        List<String> resourceRequestPaths = sysResourceService
//                .selectButtonResourcesByUserId(user.getId());
//        // 获取白名单资源
//        List<String> publicAccessUrls = securityConfigProperties.getPublicAccessUrls();
//        resourceRequestPaths.addAll(publicAccessUrls);
//        // 序列化为json字符串
//        String totalResourceRequestPaths = JSONUtil.toJsonStr(resourceRequestPaths);
//
//        // 将绑定的资源和白名单资源一起存入到redis中
//        stringRedisTemplate.opsForValue()
//                .set(CommonStrField.USER_RESOURCE.getStr() + user.getId(),
//                        totalResourceRequestPaths, jwtProperties.getExpirationTime(), TimeUnit.MILLISECONDS);
//
//        // 生成token
//        Map<String, Object> map = new HashMap<>();
//        map.put("id", user.getId());
//        map.put("name", user.getRealName());
//        map.put("avatar", user.getAvatar());
//        map.put("openId", user.getOpenId());
//        String userToken = JwtUtil.generateJwt(jwtProperties.getSecret(), map, jwtProperties.getExpirationTime());
//
//        // 将token存入redis中
//        stringRedisTemplate.opsForValue()
//                        .set(CommonStrField.USER_TOKEN.getStr() + user.getId(), userToken,
//                                jwtProperties.getExpirationTime(), TimeUnit.MILLISECONDS);
//
//        // 构造用户Vo对象返回
//        SysUserVo sysUserVo = new SysUserVo();
//        BeanUtils.copyProperties(user, sysUserVo);
//        sysUserVo.setUserToken(userToken);
//
//        return sysUserVo;
//    }


    /**
     * 使用sa-token框处理用户登录
     * @param loginDto 用户登录表单请求封装类
     * @return 返回值
     */
    @Override
    public SysUserVo login(LoginDto loginDto) {
        // 查询账号是否存在
        SysUser user = lambdaQuery()
                .eq(SysUser::getUsername, loginDto.getUsername())
                .one();
        if (user == null) {
            throw new BusinessException(ErrorConstants.USER_ACCOUNT_IS_NOT_EXIST);
        }

        // 判断账号是否禁用
        if (user.getDataState().equals("1")) {
            throw new BusinessException(ErrorConstants.USER_ACCOUNT_IS_FORBIDDEN);
        }
        // 判断密码是否正确
        if (!BCrypt.checkpw(loginDto.getPassword(), user.getPassword())) {
            throw new BusinessException(ErrorConstants.USER_ACCOUNT_OR_PASSWORD_ERROR);
        }

        // 登录
        StpUtil.login(user.getId());
        // 使用会话缓存jwtUser
        JwtUser jwtUser = new JwtUser();
        BeanUtils.copyProperties(user, jwtUser);
        SaSession session = StpUtil.getSession();
        session.set("jwtUser", jwtUser);

        // 构造用户Vo对象返回
        SysUserVo sysUserVo = new SysUserVo();
        BeanUtils.copyProperties(user, sysUserVo);
        sysUserVo.setUserToken(StpUtil.getTokenValue());

        return sysUserVo;
    }
}
